package main

import (
	"database/sql"
	"errors"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

type Users struct {
	id   int
	age  int
	name string
}

func main() {

	db, err := sql.Open("mysql", "homestead:secret@tcp(192.168.10.10)/sys")

	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	//ping
	err = db.Ping()
	if err != nil {
		panic(err.Error())
	}

	//查询
	/*
		query_sql, err := db.Prepare("select * from table_users where id = ?")
		if err != nil {
			log.Fatalln("select Query", err)
		}
		defer query_sql.Close()

		var id int
		var name string
		var age int
		err2 := query_sql.QueryRow(1).Scan(&id, &age, &name)
		if err2 != nil {
			log.Fatalln("err result", err2)
		}

		fmt.Println("select result: ", id)
		fmt.Println("select result: ", age)
		fmt.Println("select result: ", name)

	*/

	//查询err
	var age int
	err = db.QueryRow("select age from table_users where id = 1").Scan(&age)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(age)

	var name string
	err = db.QueryRow("select name from table_users where id = 2").Scan(&name)
	if err != nil {
		if err == sql.ErrNoRows {
			err = fmt.Errorf("err value %v : %w", name, err)
			// there were no rows, but otherwise no error occurred
		} else {
			log.Fatal(err)
		}
	}

	fmt.Println(name)


	//当多层调用返回的错误被一次次地包装起来，我们在调用链上游拿到的错误如何判断是否是底层的某个错误呢？
	//它递归调用 Unwrap 并判断每一层的 err 是否相等，如果有任何一层 err 和传入的目标错误相等，则返回 true。
	fmt.Println(errors.Is(err, sql.ErrNoRows))
	fmt.Println(errors.Is(err, sql.ErrConnDone))

	//而 As 则是判断类型是否相同，并提取第一个符合目标类型的错误，用来统一处理某一类错误。
	fmt.Println(errors.As(err, &sql.ErrConnDone))

}
